﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;

namespace KsWare.Breconium.Core
{
	public class SyncronizedList<T> : IList<T>
	{
		private readonly ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim();
		private readonly IList<T> innerCache = new List<T>();

		private U ReadReturn<U>(Func<U> function) {
			cacheLock.EnterReadLock();
			try {
				return function();
			} finally {
				cacheLock.ExitReadLock();
			}
		}

		private void Read(Action action) {
			cacheLock.EnterReadLock();
			try {
				action();
			} finally {
				cacheLock.ExitReadLock();
			}
		}

		private U WriteReturn<U>(Func<U> function) {
			cacheLock.EnterWriteLock();
			try {
				return function();
			} finally {
				cacheLock.ExitWriteLock();
			}
		}

		private void Write(Action action) {
			cacheLock.EnterWriteLock();
			try {
				action();
			} finally {
				cacheLock.ExitWriteLock();
			}
		}

		public T this[int index] { get { return ReadReturn(() => innerCache[index]); } set { Write(() => innerCache[index] = value); } }

		public int IndexOf(T item) { return ReadReturn(() => innerCache.IndexOf(item)); }
		public void Insert(int index, T item) { Write(() => innerCache.Insert(index, item)); }
		public void RemoveAt(int index) { Write(() => innerCache.RemoveAt(index)); }
		public void Add(T item) { Write(() => innerCache.Add(item)); }
		public void Clear() { Write(() => innerCache.Clear()); }
		public bool Contains(T item) { return ReadReturn(() => innerCache.Contains(item)); }
		public int Count { get { return ReadReturn(() => innerCache.Count); } }
		public bool IsReadOnly { get { return ReadReturn(() => innerCache.IsReadOnly); } }
		public void CopyTo(T[] array, int arrayIndex) { Read(() => innerCache.CopyTo(array, arrayIndex)); }
		public bool Remove(T item) { return WriteReturn(() => innerCache.Remove(item)); }
		public IEnumerator<T> GetEnumerator() { return ReadReturn(() => innerCache.GetEnumerator()); }
		IEnumerator IEnumerable.GetEnumerator() { return ReadReturn(() => (innerCache as IEnumerable).GetEnumerator()); }
	}

}
